package com.example.demo1.generator.codedesign.service;

import com.example.demo1.generator.codedesign.model.Column;
import com.example.demo1.generator.codedesign.model.FormType;
import com.example.demo1.generator.codedesign.model.Table;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
import org.apache.velocity.runtime.resource.loader.JarResourceLoader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.SQLException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Component
public class TemplateService implements InitializingBean {

    private VelocityEngine engine = new VelocityEngine();

    private String templatePath = "templates/codedesign/";

    @Override
    public void afterPropertiesSet() throws Exception {
        Properties p = new Properties();
        p.setProperty("input.encoding", "utf-8");
        p.setProperty("output.encoding", "utf-8");
        p.setProperty("file.resource.loader.class", StringUtils.join(Arrays
                .asList(ClasspathResourceLoader.class.getName(),
                        FileResourceLoader.class.getName(),
                        JarResourceLoader.class.getName()), ","));
        engine.init(p);
    }

    private void close(Writer writer) {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
            }
        }
    }

    protected String templateFormat(String fileName, VelocityContext context)
            throws Exception {
        Template template = engine
                .getTemplate(templatePath + fileName, "UTF-8");
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        String data = writer.toString();
        IOUtils.closeQuietly(writer);
        close(writer);
        return data;
    }

    protected VelocityContext newContext(Table table) throws SQLException {
        VelocityContext context = new VelocityContext();

        List<Column> columns = table.getColumns();
        int elementSize = 100;

        // 表单元素
        List<Column> formTexts = new ArrayList<>(elementSize);
        List<Column> formDateTimes = new ArrayList<>(elementSize);
        List<Column> formComboxs = new ArrayList<>(elementSize);
        List<Column> formTextareas = new ArrayList<>(elementSize);

        for (Column item : columns) {
            FormType formType = item.getFormType();
            if (FormType.COMBOX == formType) {
                formComboxs.add(item);
            }
            if (FormType.DATE == formType || FormType.DATETIME == formType
                    || FormType.TIME == formType) {
                formDateTimes.add(item);
            }
            if (FormType.INPUT == formType || FormType.INPUT_NUMBER == formType) {
                formTexts.add(item);
            }
            if (FormType.TEXTAREA == formType) {
                formTextareas.add(item);
            }
        }

        context.put("StringUtils", new StringUtils());

        String moduleName = table.getModuleName();
        String functionName = table.getFunctionName();
        StringBuilder packageNameSuffix = new StringBuilder();
        StringBuilder apiUrlPrefix = new StringBuilder();
        packageNameSuffix.append(moduleName);
        apiUrlPrefix.append("/").append(moduleName);
        if (StringUtils.isNotEmpty(functionName)) {
            packageNameSuffix.append(".").append(functionName);
            apiUrlPrefix.append("/").append(functionName);
        }


        context.put("table", table);
        context.put("packageNameSuffix", packageNameSuffix);
        context.put("apiUrlPrefix", apiUrlPrefix);
        context.put("codeDefine", table);
        context.put("idColumn", table.getIdColumn());
        context.put("columns", table.getColumns());

        context.put("formTexts", formTexts);
        context.put("formDateTimes", formDateTimes);
        context.put("formComboxs", formComboxs);
        context.put("formTextareas", formTextareas);

        return context;
    }

    public List<Map<String, String>> build(Table table) throws Exception {
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();
        List<String> templates = new ArrayList<>(20);
        templates.add("api.vm");
        templates.add("deletable.vm");
        templates.add("entity.vm");
        templates.add("importVo.vm");
        templates.add("mapper-xml.vm");
        templates.add("mapper.vm");
        templates.add("searchable.vm");
        templates.add("service.vm");
        templates.add("vue-api.vm");
        templates.add("vue-detail.vm");
        templates.add("vue-edit.vm");
        templates.add("vue-i18n-searchable.vm");
        templates.add("vue-i18n.vm");
        templates.add("vue-index.vm");
        templates.add("vue-router.vm");
//		templates.add("vue-searchable.vm");
        VelocityContext velocityContext = newContext(table);
        for (String template : templates) {
            String format = templateFormat(template, velocityContext);
            Map<String, String> templateResult = new HashMap<>();
            templateResult.put("name", template);
            templateResult.put("format", format);
            result.add(templateResult);
        }
        return result;
    }

    public List<Map<String, String>> build(Table table, ZipOutputStream zip) throws Exception {
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();
        List<String> templates = new ArrayList<>(20);
        templates.add("api.vm");
//        templates.add("deletable.vm");
        templates.add("entity.vm");
//        templates.add("importVo.vm");
        templates.add("mapper-xml.vm");
        templates.add("mapper.vm");
//        templates.add("searchable.vm");
        templates.add("service.vm");
//        templates.add("vue-api.vm");
        templates.add("vue-detail.vm");
        templates.add("vue-edit.vm");
//        templates.add("vue-i18n-searchable.vm");
        templates.add("vue-i18n.vm");
        templates.add("vue-index.vm");
        templates.add("vue-router.vm");
//		templates.add("vue-searchable.vm");
        VelocityContext velocityContext = newContext(table);
        for (String template : templates) {
            String format = templateFormat(template, velocityContext);
            try {
                // 添加到zip
                if (table.getFunctionName() != null) {
                    String name = getFileName(template, table.getFunctionName(), table.getClassName(), table.getLowerClassName(),
                            table.getPackageName(), table.getModuleName());

                    zip.putNextEntry(new ZipEntry(name));
                } else {
                    zip.putNextEntry(new ZipEntry(getFileName(template, table.getClassName(), table.getLowerClassName(),
                            table.getPackageName(), table.getModuleName())));
                }
                IOUtils.write(format, zip, "UTF-8");
                zip.closeEntry();
            } catch (IOException e) {
                throw new Exception("渲染模板失败，表名：" + table.getName(), e);
            }
        }
        return result;
    }

    /**
     * 获取文件名
     * 多个 getFunctionName
     */
    public static String getFileName(String template, String functionName, String className, String classname, String packageName, String moduleName) {
        String packagePath1 = "answer-java\\src\\" + "main" + File.separator + "java" + File.separator;
//		String packagePath1 = "answer-java\\liangxin-repository\\src\\" + "main" + File.separator + "java" + File.separator;
        String packagePath3 = "answer-web\\src\\";
        if (StringUtils.isNotBlank(packageName)) {
            packagePath1 += packageName.replace(".", File.separator) + File.separator;
//			packagePath2 += packageName.replace(".", File.separator) + File.separator;

        }
        if (template.equals("entity.vm")) {
            packagePath1 += "entity" + File.separator;
            return packagePath1 + moduleName + File.separator + functionName + File.separator + className + ".java";
        }

        if (template.equals("mapper.vm")) {
            packagePath1 += "mapper" + File.separator;
            return packagePath1 + moduleName + File.separator + functionName + File.separator + className + "Mapper.java";
        }
        if (template.equals("mapper-xml.vm")) {
            packagePath1 += "mapper" + File.separator;
            return packagePath1 + moduleName + File.separator + functionName + File.separator + className + "Mapper.xml";
        }
        if (template.equals("service.vm")) {
            packagePath1 += "service" + File.separator;
            return packagePath1 + moduleName + File.separator + functionName + File.separator + className + "Service.java";
        }

//		if (template.equals("deletable.vm")) {
//			packagePath1 += "deletables" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + className + "Deletable.java";
//		}
        if (template.equals("api.vm")) {
            packagePath1 += "controller" + File.separator;
            return packagePath1 + moduleName + File.separator + functionName + File.separator + className + "Api.java";
        }
//		if (template.equals("importVo.vm")) {
//			packagePath1 +="controller" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + "vo" + File.separator + className + "ImportVo.java";
//		}
//		if (template.equals("searchable.vm")) {
//			packagePath1 +="searchables" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + className + "Searchable.java";
//		}
//
//
//		if (template.contains("vue-api.vm")) {
//			return packagePath3 + "api\\" + moduleName + "\\" + functionName+ "\\" + classname.toLowerCase() + "\\" + className.toLowerCase() + ".js";
//		}
//
		if (template.contains("vue-detail.vm")) {
			return packagePath3 + "views\\" + moduleName + "\\" + functionName+ "\\" + classname.toLowerCase() + "\\" + "detail.vue";
		}

        if (template.contains("vue-index.vm")) {
            return packagePath3 + "views\\" + moduleName + "\\" + functionName + "\\" + classname.toLowerCase() + "\\" + "index.vue";
        }

        if (template.contains("vue-edit.vm")) {
            return packagePath3 + "views\\" + moduleName + "\\" + functionName + "\\" + classname.toLowerCase() + "\\" + "edit.vue";
        }

//		if (template.contains("vue-i18n-searchable.vm")) {
//			return packagePath3 + "lang\\searchable\\" + moduleName + "\\" + functionName+ "\\" + className.toLowerCase() +  ".js";
//		}

        if (template.contains("vue-i18n.vm")) {
            return packagePath3 + "lang\\temp\\" + className.toLowerCase() + "-Zh.js";
        }

        if (template.contains("vue-router.vm")) {
            return packagePath3 + "router\\modules\\" + moduleName + "\\" + functionName + "\\" + className.toLowerCase() + ".js";
        }
        return null;
    }
    /**
     * 获取文件名
     *
     */
    public static String getFileName(String template, String className, String classname, String packageName, String moduleName) {
        String packagePath1 = "answer-java\\src\\" + "main" + File.separator + "java" + File.separator;
//		String packagePath1 = "answer-java\\liangxin-repository\\src\\" + "main" + File.separator + "java" + File.separator;
        String packagePath3 = "answer-web\\src\\";
        if (StringUtils.isNotBlank(packageName)) {
            packagePath1 += packageName.replace(".", File.separator) + File.separator;
//			packagePath2 += packageName.replace(".", File.separator) + File.separator;

        }
        if (template.equals("entity.vm")) {
            packagePath1 += "entity" + File.separator;
            return packagePath1 + moduleName + File.separator + className + ".java";
        }

        if (template.equals("mapper.vm")) {
            packagePath1 += "mapper" + File.separator;
            return packagePath1 + moduleName + File.separator + className + "Mapper.java";
        }
        if (template.equals("mapper-xml.vm")) {
            packagePath1 += "mapper" + File.separator;
            return packagePath1 + moduleName + File.separator + className + "Mapper.xml";
        }
        if (template.equals("service.vm")) {
            packagePath1 += "service" + File.separator;
            return packagePath1 + moduleName + File.separator + className + "Service.java";
        }

//		if (template.equals("deletable.vm")) {
//			packagePath1 += "deletables" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + className + "Deletable.java";
//		}
        if (template.equals("api.vm")) {
            packagePath1 += "controller" + File.separator;
            return packagePath1 + moduleName + File.separator + className + "Api.java";
        }
//		if (template.equals("importVo.vm")) {
//			packagePath1 +="controller" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + "vo" + File.separator + className + "ImportVo.java";
//		}
//		if (template.equals("searchable.vm")) {
//			packagePath1 +="searchables" + File.separator;
//			return packagePath1 + moduleName + File.separator + functionName+ File.separator + className + "Searchable.java";
//		}
//
//
//		if (template.contains("vue-api.vm")) {
//			return packagePath3 + "api\\" + moduleName + "\\" + classname.toLowerCase() + "\\" + className.toLowerCase() + ".js";
//		}
//
        if (template.contains("vue-detail.vm")) {
            return packagePath3 + "views\\" + moduleName + "\\" + classname.toLowerCase() + "\\" + "detail.vue";
        }

        if (template.contains("vue-index.vm")) {
            return packagePath3 + "views\\" + moduleName  + "\\" + classname.toLowerCase() + "\\" + "index.vue";
        }

        if (template.contains("vue-edit.vm")) {
            return packagePath3 + "views\\" + moduleName  + "\\" + classname.toLowerCase() + "\\" + "edit.vue";
        }

//		if (template.contains("vue-i18n-searchable.vm")) {
//			return packagePath3 + "lang\\searchable\\" + moduleName + "\\" + className.toLowerCase() +  ".js";
//		}

        if (template.contains("vue-i18n.vm")) {
            return packagePath3 + "lang\\temp\\" + className.toLowerCase() + "-Zh.js";
        }

        if (template.contains("vue-router.vm")) {
            return packagePath3 + "router\\modules\\" + moduleName  + "\\" + className.toLowerCase() + ".js";
        }
        return null;
    }


}
